package com.information.manage.service;

import com.information.manage.basic.common.result.Result;
import com.information.manage.basic.common.utils.FileUtils;
import com.information.manage.basic.common.utils.PathUtils;
import com.information.manage.basic.common.utils.RedisUtils;
import com.information.manage.basic.common.utils.UUIDUtils;
import com.information.manage.basic.model.query.DepartmentFindByConditionQuery;
import com.information.manage.basic.model.vo.DepartmentTreeVO;
import com.information.manage.basic.service.DepartmentService;
import com.information.manage.model.dto.ClassifyStatisticDTO;
import com.information.manage.model.vo.AllStatisticVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
public class CommonService {

    @Autowired
    private DepartmentService departmentService;

    @Value("${base.classifyTypeCollection:2}")
    private Long classifyTypeCollection;

    @Autowired
    private RedisUtils redisUtils;

    @Value("${base.watchDirPath:/usr/local/tmp}")
    private String watchDirPath;

    @Value("${base.addEnclosuresDir:add_enclosures}")
    private String addEnclosuresDir;

    @Value("${nginx.domain}")
    private String nginxDomain;

    @Autowired
    private FileUtils fileUtils;

    private static final String depClassifyKey = "dep_classify";

    public List<DepartmentTreeVO> getDepartmentTreeVOList(){
        List<DepartmentTreeVO> departmentTreeVOS = null;
        if (!redisUtils.exists(depClassifyKey)){  //不存在就设置进去
            departmentTreeVOS = setDepClassifyCache();
        }else departmentTreeVOS = (List<DepartmentTreeVO>) redisUtils.get(depClassifyKey);
        return departmentTreeVOS;
    }

    /**
     * 递归处理各个分类的统计
     * @param departmentTreeVOS
     * @param collect
     * @return
     */
    public List<AllStatisticVO> recursionStatistic(List<DepartmentTreeVO> departmentTreeVOS, Map<Long, ClassifyStatisticDTO> collect){
        List<AllStatisticVO> list = new ArrayList<>();
        for (DepartmentTreeVO departmentTreeVO : departmentTreeVOS) {
            Long id = Long.valueOf(departmentTreeVO.getId());
            ClassifyStatisticDTO classifyStatisticDTO = collect.get(id);
            AllStatisticVO allStatisticVO = new AllStatisticVO();
            allStatisticVO.setClassifyId(id);
            allStatisticVO.setName(departmentTreeVO.getName());

            // 判断子分类是否存在
            List<DepartmentTreeVO> departmentTreeVOList = departmentTreeVO.getDepartmentTreeVOList();
            Long childrenCount = 0L;
            if (CollectionUtils.isNotEmpty(departmentTreeVOList)){
                List<AllStatisticVO> childList = recursionStatistic(departmentTreeVOList, collect);
                allStatisticVO.setAllStatisticVOChildren(childList);
                childrenCount = childList.stream().mapToLong(AllStatisticVO::getAll).sum();
            }

            if (classifyStatisticDTO != null){
                allStatisticVO.setAll(classifyStatisticDTO.getTotalCount() + childrenCount);
            }else {   // 可能不存在该分类的数据信息  此时设置总数为0
                allStatisticVO.setAll(childrenCount);
            }
            list.add(allStatisticVO);
        }
        return list;
    }

    public static Set<Long> getAllIds(List<DepartmentTreeVO> departmentTreeVOS) {
        Set<Long> ids = new HashSet<>();
        for (DepartmentTreeVO departmentTreeVO : departmentTreeVOS) {
            // 添加当前节点的 ID
            if (departmentTreeVO != null) {
                ids.add(Long.valueOf(departmentTreeVO.getId()));
            }

            // 递归添加子节点的 ID
            if (CollectionUtils.isNotEmpty(departmentTreeVO.getDepartmentTreeVOList())) {
                ids.addAll(getAllIds(departmentTreeVO.getDepartmentTreeVOList()));
            }
        }
        return ids;
    }

    private synchronized List<DepartmentTreeVO> setDepClassifyCache(){
        List<DepartmentTreeVO> departmentTreeVOS;
        if (!redisUtils.exists(depClassifyKey)) {  // 双重校验 避免多线程时重复执行
            DepartmentFindByConditionQuery departmentFindByConditionQuery = new DepartmentFindByConditionQuery();
            departmentFindByConditionQuery.setTypeCollection(classifyTypeCollection);
            departmentTreeVOS = departmentService.queryDepartmentByCondition(departmentFindByConditionQuery);
            redisUtils.set(depClassifyKey, departmentTreeVOS, 11L, TimeUnit.HOURS);
            return departmentTreeVOS;
        }else {
            departmentTreeVOS = (List<DepartmentTreeVO>) redisUtils.get(depClassifyKey);
        }
        return departmentTreeVOS;
    }

    public String handleAddEnclosures(List<MultipartFile> enclosures){
        // 随机生成一个uuid作为该附件的保存目录
        String randomUUID = UUIDUtils.getRandomUUID();
        // 获取当前日期
        LocalDate now = LocalDate.now();
        // 格式化日期为 "YYYY-MM-DD" 格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String formattedDate = now.format(formatter);
        // 附件的保存目录为  watchDirPath_addEnclosuresDir_时间年月日_uuid
        String dir = PathUtils.builderPath(watchDirPath, addEnclosuresDir, formattedDate, randomUUID);
        for (MultipartFile enclosure : enclosures) {
            InputStream inputStream = null;
            FileOutputStream fileOutputStream = null;
            try {
                inputStream = enclosure.getInputStream();
                File file = fileUtils.createFile(dir, enclosure.getOriginalFilename(), true);
                fileOutputStream = new FileOutputStream(file);
                byte[] bytesIn = new byte[4096];
                int read = 0;
                while ((read = inputStream.read(bytesIn)) != -1) {
                    fileOutputStream.write(bytesIn, 0, read);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            } finally {
                try {
                    if (inputStream != null) inputStream.close();
                    if (fileOutputStream != null) fileOutputStream.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return dir;
    }

    public Result<List<String>> getVisitPath(String path){
        // 检测路径下存在的所有文件
        File file = new File(path);
        if (file.isDirectory()){
            File[] files = file.listFiles();
            if (files != null && files.length == 0) {
                return Result.ok();
            }
            List<String> collect = null;
            if (files != null) {
                collect = Arrays.stream(files).map(File::getName).collect(Collectors.toList());
            }
            if (path.contains("\\")) {
                // 不能修改watchDirPath值，否则会找不到之前的数据，除非修改nginxDomain代理为根目录
                path = path.replace("\\", "/");
                return getListResult(path, collect);
            } else {
                // 不能修改watchDirPath值，否则会找不到之前的数据，除非修改nginxDomain代理为根目录
                return getListResult(path, collect);
            }
        }else {
            if (path.contains("\\")) {
                path = path.replace("\\", "/");
                String replaceFirst = path.replace(watchDirPath, "");
                String baseFile = PathUtils.builderPath(nginxDomain, replaceFirst);
                return Result.ok(Arrays.asList(baseFile));
            } else {
                // 不能修改watchDirPath值，否则会找不到之前的数据，除非修改nginxDomain代理为根目录
                String replaceFirst = path.replace(watchDirPath, "");
                String baseFile = PathUtils.builderPath(nginxDomain, replaceFirst);
                return Result.ok(Arrays.asList(baseFile));
            }
        }

    }

    private Result<List<String>> getListResult(String path, List<String> collect) {
        String replaceFirst = path.replace(watchDirPath, "");
        replaceFirst = replaceFirst.replace("\\", "/");
        String baseFile = PathUtils.builderPath(nginxDomain, replaceFirst);
        List<String> list = new ArrayList<>();
        if (collect != null) {
            for (String str : collect) {
                list.add(PathUtils.builderPath(baseFile, str));
            }
        }
        return Result.ok(list);
    }

}
